package FlowGram.Application.IDEWindow.FileManager;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTree;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.metal.MetalIconFactory;
import javax.swing.tree.*;

import FlowGram.Application.Application;
import FlowGram.Application.SimulatorWindow.Simulator.MessageBox;


/**
 * 
 * @author thackray
 *
 */
public class FileManager extends JPanel implements TreeSelectionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	
	protected JTree tree;
	protected JScrollPane treeView;
	protected ProjectFileItem currentProject;
	
	public FileManager() {
		//this.setLayout(new GridBagLayout());
		this.setBackground(Color.WHITE);
		this.setPreferredSize(new Dimension(200, 450));
		this.setLayout(new BorderLayout());
		//this.setMinimumSize(new Dimension(150, 300));
		//this.setVisible(true);
		this.makeTree();
		
		
		/*Border border = BorderFactory.createEtchedBorder();
		TitledBorder title = BorderFactory.createTitledBorder(border, "Workspace Explorer");
		title.setTitlePosition(TitledBorder.ABOVE_TOP);
		title.setTitleFont(new Font(Font.SANS_SERIF, Font.PLAIN, 18));*/
		
		JLabel title = new JLabel("Workspace Explorer");
		title.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 18));
		title.setIcon(MetalIconFactory.getTreeFolderIcon());
		this.add(title, BorderLayout.PAGE_START);
		
		
	}
	public String getCurrentProjectPath(){
		return this.currentProject.getPath();
	}
	public String getCurrentProjectTerrainsPath(){
		return this.currentProject.getTerrainsPath();
	}
	public void refresh(){
		//JTree oldTree = this.tree;
		this.remove(this.treeView);
		this.validate();
		this.makeTree();
		//expand everyone
		for(int i=0; i < this.tree.getRowCount(); i++){
			this.tree.expandRow(i);
		}
		this.validate();
		this.repaint();
		//this.tree.repaint();
		//this.repaint();
		
	}
	/*protected void makeSameExpanded(JTree oldTree, JTree newTree){
		TreeModel oldmodel = oldTree.getModel();
		if (oldmodel != null) {
	        Object root = oldmodel.getRoot();
	        System.out.println(root.toString());
	        expanderVisitor(oldmodel, root);    
	    }else{
	       System.out.println("Tree is empty.");
	    }
	}
	protected void expanderVisitor(TreeModel oldModel, TreeModel newModel, Object oldObj, Object newObj){
		int  cc;
	    cc = newModel.getChildCount(newObj);
	    for( int i=0; i < cc; i++) {
	    	DefaultMutableTreeNode newchild = (DefaultMutableTreeNode)newModel.getChild(newObj, i);
	    	if (newModel.isLeaf(newchild)){
	    		//System.out.println(child.toString());
	    	}else{
	    		DefaultMutableTreeNode oldchild = (DefaultMutableTreeNode)oldModel.getChild(oldObj, i);
	    		if(oldchild.)
	    		//System.out.print(child.toString()+"--");
	    		expanderVisitor(oldModel, newModel, oldchild, newchild); 
	        }
	    }
	}*/
	public void newProject(){
		String response = (String)JOptionPane.showInputDialog(this.getParent(), "Name of new project:", "Create New Project", JOptionPane.PLAIN_MESSAGE, null, null, "untitled");
		File f = new File(Application.getInstance().getWorkspace()+File.separator+response);
		try{
			boolean result = f.mkdir();
			if(!result){
				JOptionPane.showMessageDialog(this.getParent(),
					    "Unable to create new project!\nMake sure the project does not already exist.",
					    "Unable to Create Project",
					    JOptionPane.WARNING_MESSAGE);
			}else{
				this.refresh();
			}
		}catch(Exception e){
			JOptionPane.showMessageDialog(this.getParent(),
				    "There was an error creating the project!\n"+e.getMessage(),
				    "Error Creating Project",
				    JOptionPane.WARNING_MESSAGE);
			e.printStackTrace();
		}
	}
	public void newFile(String filename){
		this.newFile(filename, "fs");
	}
	public void newFile(String filename, String ext){
		String response = (String)JOptionPane.showInputDialog(this.getParent(), "Name of new file:", "Create New File", JOptionPane.PLAIN_MESSAGE, null, null, "Untitled."+ext);
		
		File f = new File(filename+File.separator+response);
		try {
			boolean result = f.createNewFile();
			if(!result){
				JOptionPane.showMessageDialog(this.getParent(),
					    "Unable to create new file!\nMake sure the file does not already exist.",
					    "Unable to Create File",
					    JOptionPane.WARNING_MESSAGE);
			}else{
				this.refresh();
			}
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this.getParent(),
				    "There was an error creating the file!\n"+e.getMessage(),
				    "Error Creating File",
				    JOptionPane.WARNING_MESSAGE);
			e.printStackTrace();
		}
	}
	public void deleteFile(String filename){
		int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to delete this file?", "Confirm Delete File", JOptionPane.YES_NO_OPTION);
		if(result == JOptionPane.YES_OPTION){
			File f = new File(filename);
			if(f.exists()){
				f.delete();
				this.refresh();
			}
		}
	}
	
	protected void openFile(String filename, String type) throws IOException{
		File f = new File(filename);
		if(f.isFile()){
			Application app = Application.getInstance();
			if(type.equals("code"))
				try {
					{
						//JOptionPane.showMessageDialog(this.getParent(), "Opening code file:\n"+filename);
						app.getMainWindow().getFileHost().openFile(f.getPath());
						app.showIDEWindow();
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			else if(type.equals("terrain")){
				app.getSimulationWindow().setTerrain(f.getPath());
				app.showSimulationWindow();
				//JOptionPane.showMessageDialog(this.getParent(), "Opening Terrain file:\n"+filename);
			}
		}
	}
	protected void renameFile(String oldFilename){
		File f = new File(oldFilename);
		String response = (String)JOptionPane.showInputDialog(this.getParent(), "Rename file "+f.getName(), "Rename File", JOptionPane.PLAIN_MESSAGE, null, null, f.getName());
	
		if((response != null) && (response.length() > 0)) {
			File nf = new File(f.getParent()+File.separator+response);
			if(nf.exists()){
				JOptionPane.showMessageDialog(this.getParent(),
					    "This file already exists!",
					    "Error",
					    JOptionPane.WARNING_MESSAGE);
				this.renameFile(oldFilename);
				return;
			}
			JOptionPane.showMessageDialog(this.getParent(),
				    "renaming "+oldFilename+" to "+nf.getPath());
			if(f.renameTo(nf)){
				this.refresh();
				System.out.println("renaming successful");
				return;
			}else{
				JOptionPane.showMessageDialog(this.getParent(),
					    "There was an error renaming the file!",
					    "Error",
					    JOptionPane.WARNING_MESSAGE);
				return;
			}
		}else{
			JOptionPane.showMessageDialog(this.getParent(),
				    "New filename is invalid!",
				    "Error",
				    JOptionPane.WARNING_MESSAGE);
			this.renameFile(oldFilename);
			return;
		}
	}
	
	
	protected void makeTree(){
		this.tree = new JTree(this.buildNodes());
		this.tree.setShowsRootHandles(true);
		this.tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

		//Listen for when the selection changes.
		this.tree.addTreeSelectionListener(this);
		this.tree.addMouseListener(this.getTreeMouseAdapter());
		this.tree.setEditable(true);
		this.tree.setCellEditor(new WorkspaceTreeCellEditor(this.tree, new DefaultTreeCellRenderer()));
		this.treeView = new JScrollPane(this.tree);
		this.treeView.setBorder(BorderFactory.createEtchedBorder());
		this.add(this.treeView, BorderLayout.CENTER);
		this.treeView.validate();
		this.treeView.repaint();
	}
	protected TreeNode buildNodes(){
		DefaultMutableTreeNode top = new DefaultMutableTreeNode("Workspace");
		
		List<ProjectFileItem> projs = this.findProjects(Application.getInstance().getWorkspace());
		for(int i=0; i<projs.size(); i++){
			ProjectFileItem itm = projs.get(i);
			DefaultMutableTreeNode node = new DefaultMutableTreeNode(itm);
			List<CodeFileItem> citms = itm.getCodeFiles();
			for(int j=0; j< citms.size(); j++){
				DefaultMutableTreeNode cnode = new DefaultMutableTreeNode(citms.get(j));
				node.add(cnode);
			}
			DefaultMutableTreeNode terrTop = new DefaultMutableTreeNode("Terrains");
			List<TerrainFileItem> titms = itm.getTerrainFiles();
			for(int j=0; j< titms.size(); j++){
				DefaultMutableTreeNode tnode = new DefaultMutableTreeNode(titms.get(j));
				terrTop.add(tnode);
			}
			node.add(terrTop);
			top.add(node);
		}
		return top;
	}
	
	protected List<ProjectFileItem> findProjects(String workspacePath){
		List<ProjectFileItem> projects = new ArrayList<ProjectFileItem>();
		File workspace = new File(workspacePath);
		if(workspace.isDirectory()){
			File[] contents = workspace.listFiles();
			for(int i=0; i < contents.length; i++){
				File f = contents[i];
				if(f.isDirectory()){
					projects.add(this.visitProject(f));
				}
			}
		}
		this.currentProject = projects.get(0);
		return projects;
	}
	protected ProjectFileItem visitProject(File proj){
		ProjectFileItem project = new ProjectFileItem(proj.getPath());
		
		File[] contents = proj.listFiles();
		for(int i=0; i < contents.length; i++){
			File f = contents[i];
			if(f.isDirectory() && f.getName().equalsIgnoreCase("terrains")){
				File[] terrContents = f.listFiles();
				for(int j=0; j < terrContents.length; j++){
					TerrainFileItem file = this.visitTerrainFile(terrContents[j]);
					file.project = project;
					project.addTerrainFile(file);
				}
			}else{
				CodeFileItem file = this.visitCodeFile(f);
				file.project = project;
				project.addCodeFile(file);
			}
		}
		return project;
	}
	protected CodeFileItem visitCodeFile(File path){
		CodeFileItem item = new CodeFileItem(path.getPath());
		return item;
	}
	protected TerrainFileItem visitTerrainFile(File path){
		TerrainFileItem item = new TerrainFileItem(path.getPath());
		return item;
	}

	@Override
	public void valueChanged(TreeSelectionEvent e) {
		//Returns the last path element of the selection.
		//This method is useful only when the selection model allows a single selection.
	    DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

	    if (node == null){
		    //Nothing is selected.     
		    return;
	    }

	    if(node.getUserObject() instanceof CodeFileItem){
			CodeFileItem itm = (CodeFileItem)node.getUserObject();
			this.currentProject = itm.getProject();
			
		}else if(node.getUserObject() instanceof TerrainFileItem){
			TerrainFileItem itm = (TerrainFileItem)node.getUserObject();
			this.currentProject = itm.getProject();
		}else if(node.getUserObject() instanceof ProjectFileItem){
			ProjectFileItem itm = (ProjectFileItem)node.getUserObject();
			this.currentProject = itm;
		}
	}
	protected void treeNodeDoubleClick(TreePath path) throws IOException{
		DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
		if(node.getUserObject() instanceof CodeFileItem){
			CodeFileItem itm = (CodeFileItem)node.getUserObject();
			this.openFile(itm.getPath(), "code");
			
		}else if(node.getUserObject() instanceof TerrainFileItem){
			TerrainFileItem itm = (TerrainFileItem)node.getUserObject();
			this.openFile(itm.getPath(), "terrain");
		}
	}
	protected MouseAdapter getTreeMouseAdapter(){
		MouseAdapter ma = new MouseAdapter() {
            private void myPopupEvent(MouseEvent e) {
                    int x = e.getX();
                    int y = e.getY();
                    JTree tree = (JTree)e.getSource();
                    TreePath path = tree.getPathForLocation(x, y);
                    if (path == null)
                            return; 

                    tree.setSelectionPath(path);

                    DefaultMutableTreeNode obj = (DefaultMutableTreeNode)path.getLastPathComponent();
                    JPopupMenu popup = new JPopupMenu();
                    
                    if(obj.getUserObject() instanceof ProjectFileItem){
                    	final ProjectFileItem usrObj = (ProjectFileItem)obj.getUserObject();
                    	JMenuItem newCodeFileMenuItem = new JMenuItem("New Code File");
                    	newCodeFileMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                FileManager.this.newFile(usrObj.getPath());
                            }
                        });
                    	popup.add(newCodeFileMenuItem);
                    	
                    	JMenuItem newTerrainFileMenuItem = new JMenuItem("New Terrain File");
                    	newTerrainFileMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                FileManager.this.newFile(usrObj.getTerrainsPath());
                            }
                        });
                    	popup.add(newTerrainFileMenuItem);
                    	
                    }else if(obj.getUserObject() instanceof CodeFileItem){
                    	final CodeFileItem usrObj = (CodeFileItem)obj.getUserObject();
                    	
                    	JMenuItem openMenuItem = new JMenuItem("Open");
                    	openMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                try {
									FileManager.this.openFile(usrObj.getPath(), "code");
								} catch (IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
                            }
                        });
                    	popup.add(openMenuItem);
                    	popup.add(new JSeparator());
                    	
                    	JMenuItem deleteMenuItem = new JMenuItem("Delete");
                    	deleteMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                FileManager.this.deleteFile(usrObj.getPath());
                            }
                        });
                    	popup.add(deleteMenuItem);
                    	JMenuItem renameMenuItem = new JMenuItem("Rename");
                    	renameMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                FileManager.this.renameFile(usrObj.getPath());
                            }
                        });
                    	popup.add(renameMenuItem);
                    	
                    }else if(obj.getUserObject() instanceof TerrainFileItem){
                    	final TerrainFileItem usrObj = (TerrainFileItem)obj.getUserObject();
                    	
                    	JMenuItem openMenuItem = new JMenuItem("Open");
                    	openMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                try {
									FileManager.this.openFile(usrObj.getPath(), "terrain");
								} catch (IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
                            }
                        });
                    	popup.add(openMenuItem);
                    	popup.add(new JSeparator());
                    	JMenuItem deleteMenuItem = new JMenuItem("Delete");
                    	deleteMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                FileManager.this.deleteFile(usrObj.getPath());
                            }
                        });
                    	popup.add(deleteMenuItem);
                    	JMenuItem renameMenuItem = new JMenuItem("Rename");
                    	renameMenuItem.addActionListener(new ActionListener() {
                            public void actionPerformed(ActionEvent event) {
                                FileManager.this.renameFile(usrObj.getPath());
                            }
                        });
                    	popup.add(renameMenuItem);
                    	
                    }
                    if(popup.getComponentCount() > 0){
                    	popup.addSeparator();
                    }
                    
                    JMenuItem refreshMenuItem = new JMenuItem("Refresh");
                    refreshMenuItem.setIcon(Application.loadIcon("general/Refresh16.gif"));
                    refreshMenuItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent event) {
                            FileManager.this.refresh();
                        }
                    });
                	popup.add(refreshMenuItem);
                    
                    //String label = "popup: " + obj;
                    //popup.add(new JMenuItem(label));
                    popup.show(tree, x, y);
            }
            public void mousePressed(MouseEvent e) {
                    if (e.isPopupTrigger()){
                    	myPopupEvent(e);
                    }else{
                    	int selRow = tree.getRowForLocation(e.getX(), e.getY());
                    	TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
        				if(selRow != -1) {
        					if(e.getClickCount() == 1) {
        						//mySingleClick(selRow, selPath);
        					}else if(e.getClickCount() == 2) {
        						try {
									treeNodeDoubleClick(selPath);
								} catch (IOException e1) {
									// TODO Auto-generated catch block
									e1.printStackTrace();
								}
        					}
        				}
                    }
            }
            public void mouseReleased(MouseEvent e) {
                    if (e.isPopupTrigger()) myPopupEvent(e);
            }
		};
		return ma;
	}
}
